﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using WebIM.API.Common.Exceptions;
using WebIM.API.Entities;
using WebIM.API.Thirdparty.Easemob;
using WebIM.API.Thirdparty.Easemob.Models;
using WebIM.API.Utilities;

namespace WebIM.API.Services
{
    /// <summary>
    /// 环信令牌管理
    /// </summary>
    public class EasemobAuthTokenStoreService : IEasemobAuthTokenStore
    {
        private readonly IEasemobSettings _settings;
        private readonly IImAccountService _accountService;
        private readonly HttpClient _client;
        private readonly ILogger<EasemobAuthTokenStoreService> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="settings">IM Settings</param>
        /// <param name="accountService">IMAccount Service</param>
        /// <param name="factory">HttpClient Factory</param>
        /// <param name="logger">Logger</param>
        public EasemobAuthTokenStoreService(IEasemobSettings settings, IImAccountService accountService,
            IHttpClientFactory factory, ILogger<EasemobAuthTokenStoreService> logger)
        {
            _settings = settings;
            _accountService = accountService;
            _logger = logger;
            _client = factory.CreateClient();
            _client.BaseAddress = new Uri("http://a1.easemob.com");
            _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }

        /// <inheritdoc />
        public async Task<string> GetTokenAsync()
        {
            ImAccount account = await _accountService.GetAsync(_settings.AppKey);

            if (account == null)
            {
                account = new ImAccount()
                {
                    AppKey = _settings.AppKey,
                    AppName = _settings.AppName,
                    OrgName = _settings.OrgName,
                    ClientId = _settings.ClientId,
                    ClientSecret = _settings.ClientSecret,
                    CreatedAt = DateUtils.Timestamp(),
                };
                account = await _accountService.AddSync(account);
            }

            if (account.AccessTokenIsExpired())
            {
                var uri = $"/{account.OrgName}/{account.AppName}/token";
                // 获取令牌
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
                var parameters = new Dictionary<string, string>();
                parameters["grant_type"] = "client_credentials";
                parameters["client_id"] = _settings.ClientId;
                parameters["client_secret"] = _settings.ClientSecret;
                request.Content = new StringContent(JsonSerializer.Serialize(parameters),
                    Encoding.UTF8,
                    "application/json");
                var response = await _client.SendAsync(request);
                // response.EnsureSuccessStatusCode();
                var stream = await response.Content.ReadAsStreamAsync();

                if (response.IsSuccessStatusCode)
                {
                    var output = await JsonSerializer.DeserializeAsync<GetAccessTokenOutput>(stream,
                        new JsonSerializerOptions {IgnoreNullValues = true, PropertyNameCaseInsensitive = true});

                    if (output == null)
                    {
                        throw new MessageCodeException(500, "环信接口返回数据无效");
                    }

                    int result = await _accountService.UpdateTokenAsync(account.AppKey, output.AccessToken,
                        output.ExpiresIn,
                        output.Application);
                    _logger.LogInformation("更新AccessToken [ id = {}, token = {}, result = {} ]", account.AppKey,
                        output.AccessToken, result);

                    return output.AccessToken;
                }
                else
                {
                    var output = await JsonSerializer.DeserializeAsync<BaseErrorResponse>(stream,
                        new JsonSerializerOptions {IgnoreNullValues = true, PropertyNameCaseInsensitive = true});

                    if (output == null)
                    {
                        throw new MessageCodeException(500, "环信接口返回数据无效");
                    }

                    throw new MessageCodeException(500, output.GetFormatMessage());
                }
            }

            return account.AccessToken;
        }
    }
}